#include "LockFile.h"
#include "Logger.h"

LockFile :: LockFile ( const char* nombre, bool debug ) {
	this->nombre = string(nombre);
	//Inicializa la estructura del lock (lock de escritura, sobre todo el file, y le pasa el pid)
	this->fl.l_type = F_WRLCK;
	this->fl.l_whence = SEEK_SET;
	this->fl.l_start = 0;
	this->fl.l_len = 0;
	this->fl.l_pid = getpid ();
	//Luego se abre el archivo para escritura (lo crea si no existe)
	this->fd = open ( this->nombre.c_str(),O_CREAT|O_WRONLY,0777 );
	if(this->fd < 0)
	{
		string error = "Se produjo un error al intentar abrir el archivo ";
		error.append(this->nombre);
		throw error;
	}
	this->debug = debug;
}

void LockFile :: tomarLock (bool cancelLogging) {
	if(!cancelLogging) {
		Logger* log = Logger::Instance(debug);
		log->writeToLogFile("Tomando lock de archivo " + this->nombre + "\n");
	}
	//Setea el tipo de lock (de escritura)
	this->fl.l_type = F_WRLCK;
	if(fcntl ( this->fd,F_SETLKW,&(this->fl) )==-1)
	{
		string error = "Error al intentar tomar el lock de escritura sobre el archivo ";
		error.append(this->nombre);
		throw error;
	}
}

void LockFile :: liberarLock (bool cancelLogging) {
	if(!cancelLogging) {
		Logger* log = Logger::Instance(debug);
		log->writeToLogFile("Liberando lock de archivo " + this->nombre + "\n");
	}
	//Setea el tipo de lock (liberar lock)
	this->fl.l_type = F_UNLCK;
	if(fcntl ( this->fd,F_SETLK,&(this->fl) )==-1)
	{
		string error = "Error al intentar liberar el lock de escritura sobre el archivo ";
		error.append(this->nombre);
		throw error;
	}
}

void LockFile :: escribir ( const char* buffer,int buffsize ) {
	//Se posiciona al final del archivo
	if(lseek ( this->fd,0,SEEK_END )==-1)
	{
		string error = "Se produjo un error al intentar posicionarse al final del archivo ";
		error.append(this->nombre);
		throw error;
	}
	//Escribe el buffer recibido por parámetro en el archivo
	if(write ( this->fd,buffer,buffsize )==-1)
	{
		string error = "Se produjo un error al intentar escribir en el archivo ";
		error.append(this->nombre);
		throw  error;
	}
}

void LockFile :: reemplazar ( const char* buffer,int buffsize ) {
	//Borra el contenido del archivo y escribe el buffer recibido por parámetro
	if(ftruncate(this->fd, 0)==-1)
	{
		string error = "Se produjo un error al intentar truncar el archivo ";
		error.append(this->nombre);
		throw error;
	}
	escribir(buffer, buffsize);
}

LockFile :: ~LockFile () {
	if(close ( this->fd )==-1)
	{
		string error = "Se produjo un error al intentar cerrar el archivo ";
		error.append(this->nombre);
		throw  error;
	}
}
